]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
[ShellTrayIcon] add ShellTrayIcon, make ShellTrayManager use it
authorDan Winship <danw@gnome.org>
Wed, 8 Sep 2010 02:27:08 +0000 (22:27 -0400)
committerDan Winship <danw@gnome.org>
Thu, 23 Sep 2010 13:49:47 +0000 (09:49 -0400)
The actor emitted by ShellTrayManager is now ShellTrayIcon, a subclass
of ShellGtkEmbed which has several properties on it which are (or will
soon be) useful to the shell.

Part of the rearranging to use ShellTrayIcon means that we now show
the ShellEmbeddedWindow before creating its ShellGtkEmbed, which
requires a few modifications to ShellEmbeddedWindow (notably, telling
it at construct time what stage it will be drawn on, since it needs to
know that before it has a ShellGtkEmbed now).

https://bugzilla.gnome.org/show_bug.cgi?id=608869

js/ui/panel.js
src/Makefile.am
src/shell-embedded-window.c
src/shell-embedded-window.h
src/shell-tray-icon.c [new file with mode: 0644]
src/shell-tray-icon.h [new file with mode: 0644]
src/shell-tray-manager.c

index 1abcad0ff142aeff0a0cdeb2c9f538639bee2a45..4c3206c9bb5639c15a758df919d054d155602b60 100644 (file)
@@ -885,7 +885,9 @@ Panel.prototype = {
                          });
     },
 
-    _onTrayIconAdded: function(o, icon, wmClass) {
+    _onTrayIconAdded: function(o, icon) {
+        let wmClass = icon.wm_class.toLowerCase();
+
         icon.height = PANEL_ICON_SIZE;
 
         let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
index c47d834fe1757de489cd5652824a27f7b3d288a8..db97ef2e6b1219c7dd9b54824d6e9a550f5cec54 100644 (file)
@@ -74,6 +74,7 @@ shell_public_headers_h =              \
        shell-perf-log.h                \
        shell-slicer.h                  \
        shell-stack.h                   \
+       shell-tray-icon.h               \
        shell-tray-manager.h            \
        shell-uri-util.h                \
        shell-window-tracker.h          \
@@ -104,6 +105,7 @@ libgnome_shell_la_SOURCES =         \
        shell-perf-log.c                \
        shell-slicer.c                  \
        shell-stack.c                   \
+       shell-tray-icon.c               \
        shell-tray-manager.c            \
        shell-uri-util.c                \
        shell-window-tracker.c          \
index 8da3f1486267ad9a715a1325e34bead1c57d714e..a3b9153ae7833ba5c0f29dfa44d577cce6d24d80 100644 (file)
 
 G_DEFINE_TYPE (ShellEmbeddedWindow, shell_embedded_window, GTK_TYPE_WINDOW);
 
+enum {
+   PROP_0,
+
+   PROP_STAGE
+};
+
 struct _ShellEmbeddedWindowPrivate {
   ShellGtkEmbed *actor;
 
   GdkRectangle position;
+  Window stage_xwindow;
 };
 
 /*
@@ -87,22 +94,9 @@ static void
 shell_embedded_window_realize (GtkWidget *widget)
 {
   ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
-  ClutterActor *stage;
-  Window stage_xwindow;
 
   GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->realize (widget);
 
-  stage = clutter_actor_get_stage (CLUTTER_ACTOR (window->priv->actor));
-
-  /* Clutter is buggy and will realize an actor when it has a parent
-   * but no grandparent; this is a workaround until
-   * http://bugzilla.openedhand.com/show_bug.cgi?id=1138 is fixed - we
-   * only have one stage in the shell in any case.
-   */
-  if (!stage)
-    stage = clutter_stage_get_default ();
-
-  stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
 
   /* Using XReparentWindow() is simpler than using gdk_window_reparent(),
    * since it avoids maybe having to create a new foreign GDK window for
@@ -113,7 +107,7 @@ shell_embedded_window_realize (GtkWidget *widget)
    */
   XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
                    GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget)),
-                   stage_xwindow,
+                   window->priv->stage_xwindow,
                    window->priv->position.x, window->priv->position.y);
 }
 
@@ -143,6 +137,27 @@ shell_embedded_window_check_resize (GtkContainer *container)
     clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
 }
 
+static void
+shell_embedded_window_set_property (GObject         *object,
+                                    guint            prop_id,
+                                    const GValue    *value,
+                                    GParamSpec      *pspec)
+{
+  ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object);
+
+  switch (prop_id)
+    {
+    case PROP_STAGE:
+      window->priv->stage_xwindow =
+        clutter_x11_get_stage_window (g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
 static GObject *
 shell_embedded_window_constructor (GType                  gtype,
                                    guint                  n_properties,
@@ -177,6 +192,7 @@ shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass)
 
   g_type_class_add_private (klass, sizeof (ShellEmbeddedWindowPrivate));
 
+  object_class->set_property    = shell_embedded_window_set_property;
   object_class->constructor     = shell_embedded_window_constructor;
 
   widget_class->show            = shell_embedded_window_show;
@@ -185,6 +201,14 @@ shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass)
   widget_class->configure_event = shell_embedded_window_configure_event;
 
   container_class->check_resize    = shell_embedded_window_check_resize;
+
+  g_object_class_install_property (object_class,
+                                   PROP_STAGE,
+                                   g_param_spec_object ("stage",
+                                                        "Stage",
+                                                        "ClutterStage to embed on",
+                                                        CLUTTER_TYPE_STAGE,
+                                                        G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -207,8 +231,9 @@ _shell_embedded_window_set_actor (ShellEmbeddedWindow  *window,
 
   window->priv->actor = actor;
 
-  if (gtk_widget_get_visible (GTK_WIDGET (window))
-      && CLUTTER_ACTOR_IS_REALIZED (actor))
+  if (actor &&
+      CLUTTER_ACTOR_IS_REALIZED (actor) &&
+      gtk_widget_get_visible (GTK_WIDGET (window)))
     gtk_widget_map (GTK_WIDGET (window));
 }
 
@@ -267,8 +292,9 @@ _shell_embedded_window_unrealize (ShellEmbeddedWindow *window)
  * Public API
  */
 GtkWidget *
-shell_embedded_window_new (void)
+shell_embedded_window_new (ClutterStage *stage)
 {
   return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW,
+                       "stage", stage,
                        NULL);
 }
index 91923a657e20eb0e352c051799f859a896a90b7d..145bac3a99e057b8969bd2fb84e2e3ccccf8cb56 100644 (file)
@@ -3,6 +3,7 @@
 #define __SHELL_EMBEDDED_WINDOW_H__
 
 #include <gtk/gtk.h>
+#include <clutter/clutter.h>
 
 #define SHELL_TYPE_EMBEDDED_WINDOW                 (shell_embedded_window_get_type ())
 #define SHELL_EMBEDDED_WINDOW(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_EMBEDDED_WINDOW, ShellEmbeddedWindow))
@@ -29,6 +30,6 @@ struct _ShellEmbeddedWindowClass
 };
 
 GType shell_embedded_window_get_type (void) G_GNUC_CONST;
-GtkWidget *shell_embedded_window_new (void);
+GtkWidget *shell_embedded_window_new (ClutterStage *stage);
 
 #endif /* __SHELL_EMBEDDED_WINDOW_H__ */
diff --git a/src/shell-tray-icon.c b/src/shell-tray-icon.c
new file mode 100644 (file)
index 0000000..dce8630
--- /dev/null
@@ -0,0 +1,168 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+#include "config.h"
+
+#include "shell-tray-icon.h"
+#include "shell-gtk-embed.h"
+#include "shell-window-tracker.h"
+#include "gtk-compat.h"
+#include "tray/na-tray-child.h"
+#include <gdk/gdkx.h>
+#include "st.h"
+
+enum {
+   PROP_0,
+
+   PROP_PID,
+   PROP_TITLE,
+   PROP_WM_CLASS
+};
+
+struct _ShellTrayIconPrivate
+{
+  NaTrayChild *socket;
+
+  pid_t pid;
+  char *title, *wm_class;
+};
+
+G_DEFINE_TYPE (ShellTrayIcon, shell_tray_icon, SHELL_TYPE_GTK_EMBED);
+
+static void
+shell_tray_icon_finalize (GObject *object)
+{
+  ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+
+  g_free (icon->priv->title);
+  g_free (icon->priv->wm_class);
+
+  G_OBJECT_CLASS (shell_tray_icon_parent_class)->finalize (object);
+}
+
+static void
+shell_tray_icon_constructed (GObject *object)
+{
+  GdkWindow *icon_app_window;
+  ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+  ShellEmbeddedWindow *window;
+  GdkDisplay *display;
+  Window plug_xid;
+  Atom _NET_WM_PID, type;
+  int result, format;
+  gulong nitems, bytes_after, *val = NULL;
+
+  /* We do all this now rather than computing it on the fly later,
+   * because the shell may want to see their values from a
+   * tray-icon-removed signal handler, at which point the plug has
+   * already been removed from the socket.
+   */
+
+  g_object_get (object, "window", &window, NULL);
+  g_return_if_fail (window != NULL);
+  icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window)));
+  g_object_unref (window);
+
+  icon->priv->title = na_tray_child_get_title (icon->priv->socket);
+  na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class);
+
+  icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
+  plug_xid = GDK_WINDOW_XID (icon_app_window);
+
+  display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
+  gdk_error_trap_push ();
+  _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
+  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
+                               _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
+                               &type, &format, &nitems,
+                               &bytes_after, (guchar **)&val);
+  if (!gdk_error_trap_pop () &&
+      result == Success &&
+      type == XA_CARDINAL &&
+      nitems == 1)
+    icon->priv->pid = *val;
+
+  if (val)
+    XFree (val);
+}
+
+static void
+shell_tray_icon_get_property (GObject         *object,
+                              guint            prop_id,
+                              GValue          *value,
+                              GParamSpec      *pspec)
+{
+  ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
+
+  switch (prop_id)
+    {
+    case PROP_PID:
+      g_value_set_uint (value, icon->priv->pid);
+      break;
+
+    case PROP_TITLE:
+      g_value_set_string (value, icon->priv->title);
+      break;
+
+    case PROP_WM_CLASS:
+      g_value_set_string (value, icon->priv->wm_class);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+shell_tray_icon_class_init (ShellTrayIconClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ShellTrayIconPrivate));
+
+  object_class->get_property = shell_tray_icon_get_property;
+  object_class->constructed  = shell_tray_icon_constructed;
+  object_class->finalize     = shell_tray_icon_finalize;
+
+  g_object_class_install_property (object_class,
+                                   PROP_PID,
+                                   g_param_spec_uint ("pid",
+                                                      "PID",
+                                                      "The PID of the icon's application",
+                                                      0, G_MAXUINT, 0,
+                                                      G_PARAM_READABLE));
+  g_object_class_install_property (object_class,
+                                   PROP_TITLE,
+                                   g_param_spec_string ("title",
+                                                        "Title",
+                                                        "The icon's window title",
+                                                        NULL,
+                                                        G_PARAM_READABLE));
+  g_object_class_install_property (object_class,
+                                   PROP_WM_CLASS,
+                                   g_param_spec_string ("wm-class",
+                                                        "WM Class",
+                                                        "The icon's window WM_CLASS",
+                                                        NULL,
+                                                        G_PARAM_READABLE));
+}
+
+static void
+shell_tray_icon_init (ShellTrayIcon *icon)
+{
+  icon->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon, SHELL_TYPE_TRAY_ICON,
+                                            ShellTrayIconPrivate);
+}
+
+/*
+ * Public API
+ */
+ClutterActor *
+shell_tray_icon_new (ShellEmbeddedWindow *window)
+{
+  g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL);
+
+  return g_object_new (SHELL_TYPE_TRAY_ICON,
+                       "window", window,
+                       NULL);
+}
diff --git a/src/shell-tray-icon.h b/src/shell-tray-icon.h
new file mode 100644 (file)
index 0000000..88e2a14
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __SHELL_TRAY_ICON_H__
+#define __SHELL_TRAY_ICON_H__
+
+#include "shell-gtk-embed.h"
+
+#define SHELL_TYPE_TRAY_ICON                 (shell_tray_icon_get_type ())
+#define SHELL_TRAY_ICON(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIcon))
+#define SHELL_TRAY_ICON_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
+#define SHELL_IS_TRAY_ICON(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_TRAY_ICON))
+#define SHELL_IS_TRAY_ICON_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_TRAY_ICON))
+#define SHELL_TRAY_ICON_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
+
+typedef struct _ShellTrayIcon        ShellTrayIcon;
+typedef struct _ShellTrayIconClass   ShellTrayIconClass;
+typedef struct _ShellTrayIconPrivate ShellTrayIconPrivate;
+
+struct _ShellTrayIcon
+{
+    ShellGtkEmbed parent;
+
+    ShellTrayIconPrivate *priv;
+};
+
+struct _ShellTrayIconClass
+{
+    ShellGtkEmbedClass parent_class;
+};
+
+
+GType         shell_tray_icon_get_type (void) G_GNUC_CONST;
+ClutterActor *shell_tray_icon_new      (ShellEmbeddedWindow *window);
+
+#endif /* __SHELL_TRAY_ICON_H__ */
index f7c172a380cfd9758627195a83430a6da0b8fde7..330e8116926b6ebcf792c40df78ab064aff2e379 100644 (file)
@@ -13,7 +13,7 @@
 #include "shell-tray-manager.h"
 #include "na-tray-manager.h"
 
-#include "shell-gtk-embed.h"
+#include "shell-tray-icon.h"
 #include "shell-embedded-window.h"
 #include "shell-global.h"
 
@@ -30,7 +30,6 @@ typedef struct {
   GtkWidget *socket;
   GtkWidget *window;
   ClutterActor *actor;
-  gboolean emitted_plugged;
 } ShellTrayManagerChild;
 
 enum {
@@ -159,11 +158,9 @@ shell_tray_manager_class_init (ShellTrayManagerClass *klass)
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
                   NULL, NULL,
-                  gi_cclosure_marshal_generic,
-                  G_TYPE_NONE, 3,
-                  CLUTTER_TYPE_ACTOR,
-                  G_TYPE_STRING,
-                  G_TYPE_STRING);
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1,
+                  CLUTTER_TYPE_ACTOR);
   shell_tray_manager_signals[TRAY_ICON_REMOVED] =
     g_signal_new ("tray-icon-removed",
                   G_TYPE_FROM_CLASS (klass),
@@ -280,31 +277,14 @@ on_plug_added (GtkSocket        *socket,
                ShellTrayManager *manager)
 {
   ShellTrayManagerChild *child;
-  char *wm_class, *lower_wm_class;
-  char *title;
 
-  child = g_hash_table_lookup (manager->priv->icons, socket);
-  /* Only emit this signal once; the point of waiting until we
-   * get the first plugged notification is to be able to get the WM_CLASS
-   * from the child window.  But we don't want to emit this signal twice
-   * if for some reason the socket gets replugged.
-   */
-  if (child->emitted_plugged)
-    return;
-  child->emitted_plugged = TRUE;
+  g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager);
 
-  na_tray_child_get_wm_class (NA_TRAY_CHILD (socket), NULL, &wm_class);
-  if (!wm_class)
-    return;
-
-  title = na_tray_child_get_title (NA_TRAY_CHILD (socket));
+  child = g_hash_table_lookup (manager->priv->icons, socket);
 
-  lower_wm_class = g_ascii_strdown (wm_class, -1);
+  child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window));
   g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
-                 child->actor, lower_wm_class, title);
-  g_free (lower_wm_class);
-  g_free (wm_class);
-  g_free (title);
+                 child->actor);
 }
 
 static void
@@ -313,7 +293,6 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
 {
   ShellTrayManager *manager = user_data;
   GtkWidget *win;
-  ClutterActor *icon;
   ShellTrayManagerChild *child;
 
   /* We don't need the NaTrayIcon to be composited on the window we
@@ -324,7 +303,7 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
    */
   na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);
 
-  win = shell_embedded_window_new ();
+  win = shell_embedded_window_new (manager->priv->stage);
   gtk_container_add (GTK_CONTAINER (win), socket);
 
   /* The colormap of the socket matches that of its contents; make
@@ -341,9 +320,6 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
 
   gtk_widget_show_all (win);
 
-  icon = shell_gtk_embed_new (SHELL_EMBEDDED_WINDOW (win));
-
-  child->actor = g_object_ref (icon);
   g_hash_table_insert (manager->priv->icons, socket, child);
 
   g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);